﻿
// MFCTinyxml2Dlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "MFCTinyxml2.h"
#include "MFCTinyxml2Dlg.h"
#include "afxdialogex.h"

#include "tinyxml2/tinyxml2.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCTinyxml2Dlg 对话框



CMFCTinyxml2Dlg::CMFCTinyxml2Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFCTINYXML2_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCTinyxml2Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCTinyxml2Dlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CMFCTinyxml2Dlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CMFCTinyxml2Dlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON4, &CMFCTinyxml2Dlg::OnBnClickedButton4)
	ON_BN_CLICKED(IDC_BUTTON7, &CMFCTinyxml2Dlg::OnBnClickedButton7)
	ON_BN_CLICKED(IDC_BUTTON8, &CMFCTinyxml2Dlg::OnBnClickedButton8)
	ON_BN_CLICKED(IDC_BUTTON9, &CMFCTinyxml2Dlg::OnBnClickedButton9)
	ON_BN_CLICKED(IDC_BUTTON10, &CMFCTinyxml2Dlg::OnBnClickedButton10)
	ON_BN_CLICKED(IDC_BUTTON11, &CMFCTinyxml2Dlg::OnBnClickedButton11)
	ON_BN_CLICKED(IDC_BUTTON12, &CMFCTinyxml2Dlg::OnBnClickedButton12)
	ON_BN_CLICKED(IDC_BUTTON3, &CMFCTinyxml2Dlg::OnBnClickedButton3)
	ON_BN_CLICKED(IDC_BUTTON5, &CMFCTinyxml2Dlg::OnBnClickedButton5)
END_MESSAGE_MAP()


// CMFCTinyxml2Dlg 消息处理程序

BOOL CMFCTinyxml2Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CMFCTinyxml2Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCTinyxml2Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


/// <summary>
/// 
/// </summary>
/// <param name="str"></param>
/// <param name="CodePage">默认CP_UTF8，要求XML文件的编码也要是UTF-8</param>
/// <returns></returns>
wchar_t* CMFCTinyxml2Dlg::Char2Wchar(const char* str, UINT CodePage) {
	//先获取转换成宽字符后的长度
	int nLen = MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, NULL, 0);
	//声明一个宽字符类型变量，用于存放转换后的字符
	wchar_t* wstr = new wchar_t[nLen];
	//利用微软ANSI转宽字符的函数（name:ANSI字符，wname:宽字符）
	MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, wstr, nLen);

	return wstr;
}

void CMFCTinyxml2Dlg::ReadXmlText() {
	CEdit* pEditXml = (CEdit*)GetDlgItem(IDC_EDIT_XML);
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError errXml = docXml.LoadFile("XMLFile.xml");

	tinyxml2::XMLPrinter printer;
	docXml.Print(&printer);
	const char* buf = printer.CStr();
	pEditXml->SetWindowText(Char2Wchar(buf, CP_UTF8));
}

/// <summary>
/// 创建XML
/// </summary>
void CMFCTinyxml2Dlg::OnBnClickedButton1()
{
	//使用以下内容建立XMLDocument
	const char* xmlContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
	tinyxml2::XMLDocument docXml;	
	docXml.Parse(xmlContent);

	//添加root节点
	tinyxml2::XMLElement* root = docXml.NewElement("root");
	docXml.InsertEndChild(root);

	//添加message节点
	tinyxml2::XMLElement* messageNode = docXml.NewElement("message");
	messageNode->SetAttribute("username", "zhangsan");//属性
	messageNode->SetText("hello");//内容
	root->InsertEndChild(messageNode);

	//保存成XML文件
	docXml.SaveFile("XMLFile.xml");
}


/// <summary>
/// 读取XML
/// </summary>
void CMFCTinyxml2Dlg::OnBnClickedButton2()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//获取message节点
		tinyxml2::XMLElement* messageNode = root->FirstChildElement("message");

		//获取message->username属性的值
		//const char* username = messageNode->FindAttribute("username")->Value();
		const char* username = messageNode->Attribute("username");

		//获取message的内容
		const char* content = messageNode->GetText();

		//弹窗展示读取到的信息
		CString str;
		str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(username), Char2Wchar(content));
		AfxMessageBox(str);
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton4()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//循环增加3次message节点
		const char* arrUsername[3] = {"lisi","wangwu","zhaoliu"};
		for (int i = 0; i < 3; i++)
		{
			//生成新的message节点（无论在哪个节点中New，都直接在doc.NewElement）
			tinyxml2::XMLElement* messageNode = docXml.NewElement("message");
			messageNode->SetAttribute("username", arrUsername[i]);//属性
			messageNode->SetText(i);//内容
			root->InsertEndChild(messageNode);
		}

		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}

/// <summary>
/// 根据属性/值查询节点
/// </summary>
/// <param name="root">xml root节点</param>
/// <param name="elementName">要查询的节点，一般是多行的</param>
/// <param name="attributeName">节点的属性名</param>
/// <param name="attributeValue">节点的属性值</param>
/// <returns></returns>
tinyxml2::XMLElement* CMFCTinyxml2Dlg::queryXMLElementByAttribute(tinyxml2::XMLElement* root, const char* elementName, const char* attributeName, const char* attributeValue) {
	tinyxml2::XMLElement* node = root->FirstChildElement(elementName);
	while (node != NULL)
	{
		const char* value = node->Attribute(attributeName);
		//比较两个字符串char*是否相等（const char*，不能直接使用等号比较）
		if (strcmp(value, attributeValue) == 0)
			break;

		node = node->NextSiblingElement();
	}

	return node;
}

/// <summary>
/// 用属性查：wangwu
/// </summary>
void CMFCTinyxml2Dlg::OnBnClickedButton7()
{
	const char* whereUsername = "wangwu";

	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();
		tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "wangwu");

		//最后保留下的这个节点就是查询到的节点
		//弹窗展示读取到的信息
		CString str;
		str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(messageNode->Attribute("username")), Char2Wchar(messageNode->GetText()));
		AfxMessageBox(str);
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton8()
{
	CMFCTinyxml2Dlg::OnBnClickedButton7();//同理
}

/// <summary>
/// 找到username = lisi的节点，改成lisi1
/// </summary>
void CMFCTinyxml2Dlg::OnBnClickedButton9()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//查询
		tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "lisi");
		//更新
		messageNode->SetAttribute("username", "lisi1234");//改成lisi1234
		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton10()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//查询
		tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "zhaoliu");
		//更新内容
		messageNode->SetText("MY UPDATE");
		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton11()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//查询
		tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "zhaoliu");
		//删除查询到的节点
		root->DeleteChild(messageNode);
		
		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton12()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();
		//删除查询到的节点
		root->DeleteChildren();

		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton3()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {

		tinyxml2::XMLPrinter printer;
		docXml.Print(&printer);

		AfxMessageBox(Char2Wchar(printer.CStr()));
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}


void CMFCTinyxml2Dlg::OnBnClickedButton5()
{
	tinyxml2::XMLDocument docXml;
	tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");
	if (xmlError == tinyxml2::XML_SUCCESS) {
		//获取root节点
		tinyxml2::XMLElement* root = docXml.RootElement();

		//生成新的message节点（无论在哪个节点中New，都直接在doc.NewElement）
		tinyxml2::XMLElement* messageNode = docXml.NewElement("message");

		messageNode->SetAttribute("username", Ascii2Unicode2Utf8("王二麻子"));//属性
		messageNode->SetText(Ascii2Unicode2Utf8("中文内容测试"));//内容

		root->InsertEndChild(messageNode);

		//不要忘记保存一下
		docXml.SaveFile("XMLFile.xml");
	}
	else {
		AfxMessageBox(_T("load xml file failed."));
	}
}

char* CMFCTinyxml2Dlg::Ascii2Unicode2Utf8(const char* str) {
	//ASCII to Unicode(CP_ACP)
	int nLen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[nLen];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, nLen);

	//Unicode to UTF-8
	int nLenUTF8 = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* strUTF8 = new char[nLenUTF8];
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, strUTF8, nLenUTF8, NULL, NULL);

	return strUTF8;
}